/*
 * @(#)Trit.java	1.0 Mar 7, 2008
 *
 *	The MIT License
 *
 *	Copyright (c) 2008 Malachi de AElfweald <malachid@gmail.com>
 *
 *	Permission is hereby granted, free of charge, to any person obtaining a copy
 *	of this software and associated documentation files (the "Software"), to deal
 *	in the Software without restriction, including without limitation the rights
 *	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *	copies of the Software, and to permit persons to whom the Software is
 *	furnished to do so, subject to the following conditions:
 *
 *	The above copyright notice and this permission notice shall be included in
 *	all copies or substantial portions of the Software.
 *
 *	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 *	THE SOFTWARE.
 */
package org.eoti.lang;

import java.util.*;

public class Trit
implements Comparable<Trit>, Comparator<Trit>
{
	protected enum State
	{
		Negative(-1, '\u012B'), Neutral(0, '0'), Positive(1, '1');
		State(int intValue, char charValue)
		{
			this.intValue = intValue;
			this.charValue = charValue;
		}
		protected int intValue;
		protected char charValue;
		public int toInt(){return intValue;}
		public char toChar(){return charValue;}
	}

	// convenience access

	public static final Trit NEGATIVE = new Trit(State.Negative);
	public static final Trit NEUTRAL = new Trit(State.Neutral);
	public static final Trit POSITIVE = new Trit(State.Positive);

	protected State state;

	public Trit(State state){this.state = state;}
	public Trit(Trit trit){this.state = trit.state;}

	public boolean isNegative(){return state == State.Negative;}
	public boolean isNeutral(){return state == State.Neutral;}
	public boolean isPositive(){return state == State.Positive;}

	public Trit max(Trit other){return toInt() >= other.toInt() ? this : other;}
	public Trit min(Trit other){return toInt() <= other.toInt() ? this : other;}
	public Trit or(Trit other){return max(other).clone();}
	public Trit and(Trit other){return min(other).clone();}
	public Trit xor(Trit other)
	{
		if(isNegative() && other.isNegative()) return NEGATIVE.clone();
		if(isNegative() && other.isPositive()) return POSITIVE.clone();
		if(isPositive() && other.isNegative()) return POSITIVE.clone();
		return NEUTRAL.clone();
	}
	public Trit nand(Trit other){return not(and(other));}
	public Trit nor(Trit other){return not(or(other));}
	public Trit nxor(Trit other){return not(xor(other));}

	/**
	 * Invert unary operation
	 * ? becomes 1
	 * 0 becomes 0
	 * 1 becomes ?
	 */
	public Trit invert(){return not();}
	public Trit not()
	{
		switch(state)
		{
			case Negative:
				return Trit.POSITIVE.clone();
			case Positive:
				return Trit.NEGATIVE.clone();
			default:
				return Trit.NEUTRAL.clone();
		}
	}
	public Trit not(Trit other){return inequality(other);}
	public Trit inequality(Trit other)
	{
		Trit eq = equality(other);
		if(eq.isPositive()) return NEGATIVE.clone();
		if(eq.isNegative()) return POSITIVE.clone();
		return NEUTRAL.clone();
	}
	public Trit disjunction(Trit other){return or(other);}
	public Trit conjunction(Trit other){return and(other);}
    public Trit equality(Trit other)
	{
		if(state == other.state) return POSITIVE.clone();
		if(isNeutral()) return NEUTRAL.clone();
		if(other.isNeutral()) return NEUTRAL.clone();
		return NEGATIVE.clone();
	}
	public Trit implication(Trit other)
	{
		if(other.isNegative() && isNeutral()) return NEUTRAL.clone();
		if(other.isNegative() && isPositive()) return NEGATIVE.clone();
		if(other.isNeutral() && isPositive()) return NEUTRAL.clone();
		return POSITIVE.clone();
	}
	public Trit alternation(Trit other){return xor(other);}

	/**
	 * ShiftUp unary operation
	 * ? becomes 0
	 * 0 becomes 1
	 * 1 becomes 1
	 */
	public Trit shiftUp(){return NEUTRAL.implication(this);}

	/**
	 * ShiftDown unary operation
	 * ? becomes ?
	 * 0 becomes ?
	 * 1 becomes 0
	 */
	public Trit shiftDown(){return not(implication(NEUTRAL));}

	/**
	 * RotateUp unary operation
	 * ? becomes 0
	 * 0 becomes 1
	 * 1 becomes ?
	 */
	public Trit rotateUp()
	{
		/**
		 * Change to use gate logic?
		 */
		switch(state)
		{
			case Negative: return NEUTRAL.clone();
			case Neutral: return POSITIVE.clone();
			default: return NEGATIVE.clone();
		}
	}

	/**
	 * RotateDown unary operation
	 * ? becomes 1
	 * 0 becomes ?
	 * 1 becomes 0
	 */
	public Trit rotateDown()
	{
		/**
		 * Change to use gate logic?
		 */
		switch(state)
		{
			case Negative: return POSITIVE.clone();
			case Neutral: return NEGATIVE.clone();
			default: return NEUTRAL.clone();
		}
	}

	public String toString(){return ""+toChar();}
	public char toChar(){return state.toChar();}
	public int toInt(){return state.toInt();}
	public Trit clone(){return new Trit(state);}
	public boolean equals(Object obj){return (compareTo((Trit)obj) == State.Neutral.toInt());}
	public int compareTo(Trit obj){return compare(this, obj);}

	public int compare(Trit t1, Trit t2)
	{
		if(t1.state.toInt() < t2.state.toInt())
			return State.Negative.toInt();

		if(t1.state.toInt() > t2.state.toInt())
			return State.Positive.toInt();

		return State.Neutral.toInt();
	}
}